"""
-----脚本能力-----
仅可执行脚本化的历战NPC战斗
使用前请确保你的战斗序列每次都可以以完全相同的流程进行
如果需要死人也请死同一位角色，脚本无法应对随机状况

-----脚本状态-----
脚本架构：完成
已适配历战NPC：已适配全部8人，适用于台服及国际服

-----已知问题-----未解决-----
1. 大地图有概率双击，虽不影响本脚本运行，但会影响其他情况的使用。 - 增加延迟观察效果 - 待验证 - 目前稳定
-----已知问题-----已解决-----
1. 技能点击失效，推测原因为卡顿状态下，按键快于面板就绪。 - 加入重试机制 - 无复现
2. 技能面板开启失效，推测原因为过快点击致使面板关闭。 - 加入重试机制 - 无复现
3. Boost等级使用错误，加延迟无法避免。 - 加入检查及重试机制 - 无复现
-----已知问题-----状态未知-----
1. 切换角色不成功，极低概率出现 - 未应对 - 无法复现

-----后续改进计划-----
0. （优先）更新UI，战斗序列生成工具，适配分享功能
1. 角色技能使用可能需要指定目标，目前尚未适配，今后增加。
2. 角色必杀，今后增加。
3. 其他重要脚本：亚久斯特脚本，斗技大会脚本，黑龙脚本。

-----使用方法-----
修改四个使用者参数
1. 修改targeting_npc，指定目标为哪位历战NPC
2. 修改battle_sequence, 指定你设计的战斗序列
3. 修改region，指定台服或国际服，默认台服
4. 修改round_per_recover, 目前建议不修改，有能力2T以后再调高此参数
5. 在城市旅店门口启动脚本
"""

from time import *
from PyGameAutoAndroid import *

#   -------------------------------------------------------------------------------------------------
#   使用者参数部分 - 通过调整参数改变脚本功能
#   -------------------------------------------------------------------------------------------------
#   targeting_npc - 配置脚本目标为哪位历战NPC
#       可选值: 'bt_axe'    - 历战斧 - 瓦洛雷
#              'bt_bow'    - 历战弓 - 恩波格洛
#              'bt_tome'   - 历战书 - 希亚特珀利斯
#              'bt_spear'  - 历战枪 - 利布尔泰德
#              'bt_dagger' - 历战匕 - 克拉古斯比亚
#              'bt_staff'  - 历战杖 - 库利亚布鲁克
#              'bt_fan'    - 历战扇 - 桑谢德
#              'bt_blade'  - 历战剑 - 利布尔泰德

targeting_npc = "bt_staff"

#   battle_sequence - 预设战斗序列 - 此设计为临时方案
#                     由于每位玩家拥有的角色，技能，星级均不同，技能位置，队伍组成也不同，因此这段必须自己设计并提供数值
#                     此参数为object array：
#                           第1层为战斗回合层，数组有多少对象元素就有多少战斗回合
#                           第2层为战斗对象层，对象有两个字段
#                               all_boost  - 是否需要按下全体boost按钮
#                               skill_list - 只有4个元素，分别代表从上到下第1234位角色
#
#                           skill_list内为角色技能层，只有2个元素，第一个元素为使用哪个技能，第二个元素为使用几级Boost
#                           关于技能，可选值为-1, 0, 1, 2, 3, 10, 11, 12, 13
#                               -1 - 跳过本角色
#                               0  - 使用普攻
#                               1  - 使用第一个技能
#                               2  - 使用第二个技能
#                               3  - 使用第三个技能
#                               10 - 交换角色，使用普攻
#                               11 - 交换角色，使用第一个技能
#                               12 - 交换角色，使用第二个技能
#                               13 - 交换角色，使用第三个技能
#                           关于Boost，可选值为1, 2, 3, 4
#                               1  - 无Boost
#                               2  - 2级Boost
#                               3  - 3级Boost
#                               4  - 满级Boost

battle_sequence = [
    # 第1回合
    {
        'skill_list': [
            [3, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
        ],
        'all_boost': True,
    },
]

battle_sequence_1 = [
    # 第1回合
    {
        'skill_list': [
            [1, 1, 1, 0],
            [1, 1, 0, 0],
            [1, 4, 0, 0],
            [3, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第2回合
    {
        'skill_list': [
            [13, 4, 0, 0],
            [11, 4, 0, 'tikilen'],
            [13, 1, 0, 0],
            [3, 1, 0, 'elite-mercenary'],
        ],
        'all_boost': False,
    },
    # 第3回合
    {
        'skill_list': [
            [11, 1, 1, 0],
            [11, 1, 0, 0],
            [-1, 1, 0, 0],
            [12, 4, 0, 0],
        ],
        'all_boost': False,
    },
    # 第4回合
    {
        'skill_list': [
            [2, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [12, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第5回合
    {
        'skill_list': [
            [1, 1, 1, 0],
            [11, 1, 0, 0],
            [11, 4, 0, 0],
            [3, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第6回合
    {
        'skill_list': [
            [2, 1, 0, 0],
            [2, 4, 0, 0],
            [13, 1, 0, 0],
            [3, 1, 0, 'veteran-mercenary'],
        ],
        'all_boost': False,
    },
    # 第7回合
    {
        'skill_list': [
            [13, 4, 0, 0],
            [11, 4, 0, 0],
            [-1, 1, 0, 0],
            [12, 4, 0, 0],
        ],
        'all_boost': False,
    },
    # 第8回合
    {
        'skill_list': [
            [12, 1, 0, 0],
            [5, 1, 0, 0],
            [-1, 1, 0, 0],
            [11, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第9回合
    {
        'skill_list': [
            [12, 4, 0, 0],
            [1, 1, 0, 0],
            [2, 1, 0, 0],
            [11, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第10回合
    {
        'skill_list': [
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [1, 4, 0, 0],
        ],
        'all_boost': False,
    },
    # 第11回合
    {
        'skill_list': [
            [-1, 1, 0, 0],
            [2, 1, 0, 0],
            [-1, 1, 0, 0],
            [13, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第n回合 - 如有需求可以一直加下去，但要保证你的战斗流程每次都相同，不可以这次战斗4回合，下次战斗5回合
]

#   region - 区服代码
#       可选值: 'tw'    - 台服
#              'en'    - 美服
region = 'tw'

#   round_per_recover - 每次回旅店回血后连续与历战NPC战斗的场次 - 默认1次
round_per_recover = 1

#   -------------------------------------------------------------------------------------------------
#                               ※如果不懂编程或看不懂代码，从这里往下可以不用看了※
#   -------------------------------------------------------------------------------------------------
#   开发者参数部分 - 通过调整参数改变脚本性能
stability_mode = 0
turn_on_in_game_log = False
turn_on_console_log = True

valore_main_boulevard_coord = [296, 478]
emberglow_east_district_coord = [932, 452]
emberglow_laboratory_coord = [759, 347]
emberglow_laboratory_to_town_coord = [272, 544]
cragspear_slums_coord = [841, 616]
theatropolis_library_coord = [447, 416]
rippletide_residence_coord = [797, 337]

#   常数部分 - 游戏内固定参数，比如地图按钮的位置。
#   当更换设备时，由于屏幕分辨率发生变化，这些数值都会失效，放在这里统一更改，比去代码里寻找效率更高。
#   单点坐标常数
screen_center_coord = [640, 360]  # 屏幕正中
minimap_coord = [1078, 137]  # 主界面 - 小地图上箭头坐标
party_btn_coord = [215, 605]  # 主界面 - 大陆地图按钮坐标
worldmap_btn_coord = {  # 主界面 - 队伍按钮坐标
    'tw': [728, 605],
    'en': [730, 605],
}
allies_list_btn_coord = [116, 543]  # 队伍界面 - 支援者列表按钮坐标
first_ally_coord = [387, 256]  # 支援者列表 - 第一位支援者位置坐标
part_ways_btn_coord = [796, 597]  # 支援者列表 - 告别按钮位置
general_ok_btn_coord = [800, 480]  # 菜单界面 - 通用OK按钮坐标，如：确认告别的OK按钮，确认大地图前往某处的是按钮
close_menu_btn_coord = [1236, 22]  # 菜单界面 - 右上角叉按钮位置
inquire_btn_coord = [1176, 626]  # 主界面 - 打听按钮位置
impress_btn_coord = [1043, 400]  # 打听界面 - 收服按钮位置
confirm_impress_btn_coord = [763, 500]  # 收服界面 - 收服按钮位置
lower_ok_btn_coord = [800, 514]  # 菜单界面 - 低位OK按钮坐标，如：确认收服OK按钮，确认住店按钮
center_ok_btn_coord = [642, 480]  # 菜单界面 - 中间OK按钮坐标
worldmap_proceed_btn_coord = [1051, 641]  # 世界地图 - 前往这里按钮位置
skills_panel_coord = [[1150, 90],
                      [1150, 230],
                      [1150, 370],
                      [1150, 520]]
switch_character_coord = {
    'tw': [793, 626],
    'en': [1105, 635],
}
skills_coord = {
    'tw': [[[850, 170, 0, 0],
            [850, 170, 1025, 170],
            [850, 170, 1115, 170],
            [850, 170, 1200, 170]],
           [[850, 290, 0, 0],
            [850, 290, 1025, 290],
            [850, 290, 1115, 290],
            [850, 290, 1200, 290]],
           [[850, 400, 0, 0],
            [850, 400, 1025, 400],
            [850, 400, 1115, 400],
            [850, 400, 1200, 400]],
           [[850, 520, 0, 0],
            [850, 520, 1025, 520],
            [850, 520, 1115, 520],
            [850, 520, 1200, 520]]],
    'en': [[[850, 200, 0, 0],
            [850, 200, 1025, 170],
            [850, 200, 1115, 170],
            [850, 200, 1200, 170]],
           [[850, 305, 0, 0],
            [850, 305, 1025, 290],
            [850, 305, 1115, 290],
            [850, 305, 1200, 290]],
           [[850, 410, 0, 0],
            [850, 410, 1025, 400],
            [850, 410, 1115, 400],
            [850, 410, 1200, 400]],
           [[850, 525, 0, 0],
            [850, 525, 1025, 520],
            [850, 525, 1115, 520],
            [850, 525, 1200, 520]]],
}
start_battle_btn_coord = [1083, 643]
all_boost_btn_coord = [864, 643]
flee_battle_btn_coord = [535, 645]

inn_exit_coord = {
    'valore': [534, 447],
    'emberglow': [534, 447],
    'theatropolis': [645, 447],
    'rippletide': [533, 447],
    'cragspear': [526, 448],
    'clearbrook': [498, 448],
    'sunshade': [695, 404],
    'shepherds-rock': [552, 447],
}

get_town_name_by_npc = {
    'bt_axe': 'valore',
    'bt_bow': 'emberglow',
    'bt_tome': 'theatropolis',
    'bt_spear': 'rippletide',
    'bt_dagger': 'cragspear',
    'bt_staff': 'clearbrook',
    'bt_fan': 'sunshade',
    'bt_blade': 'shepherds-rock',
}

bt_npc_coord_on_minimap = {
    'bt_axe': [845, 469],
    'bt_bow': [679, 541],
    'bt_tome': [0, 0],
    'bt_spear': [0, 0],
    'bt_dagger': [727, 535],
    'bt_staff': [741, 302],
    'bt_fan': [284, 270],
    'bt_blade': [760, 391],
}

#   多点找色常数
minimap_exist = ["#E2D57E", "1|0|#E2D57E", [1078, 137, 1080, 138]]
menu_exist = {
    'tw': ["#F0EBE8", "0|1|#F0EBE8", [716, 630, 717, 632]],  # 使用了世界地图的文字做判断，以后更新会导致失效，需要更新脚本
    'en': ["#F0EBE8", "0|1|#F0EBE8", [943, 622, 944, 624]],  # 使用了Hint的文字做判断，以后更新会导致失效，需要更新脚本
}
menu_opened = {
    'tw': ["#E9E9E9", "1|1|#E9E9E9", [1235, 19, 1237, 21]],
    'en': ["#E9E9E9", "1|1|#E9E9E9", [1236, 20, 1238, 22]],
}
character_standby = ["#F0EBE8", "1|0|#F0EBE8", [681, 168, 683, 169]]
battle_idling = {
    'tw': ["#FFFFFF", "1|1|#FFFFFF", [1082, 642, 1084, 644]],
    'en': ["#FFFFFF", "1|1|#FFFFFF", [1038, 629, 1040, 631]],
}
black_screen_exist = ["#000000", "1|1|#000000", [639, 359, 641, 361]]
town_menu_opened = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [1014, 643, 1015, 645]],
    'en': ["#FFFFFF", "0|1|#FFFFFF", [1001, 636, 1002, 638]],
}
ok_move_exist = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [798, 485, 799, 487]],
    'en': ["#FFFFFF", "0|1|#FFFFFF", [783, 479, 784, 481]],
}
inquire_exist = ["#62AAAA", "0|1|#5C6F6F", [1076, 656, 1100, 658]]
inquire_menu_opened = ["#58BBB0", "1|1|#58BBB0", [1150, 279, 1159, 282]]
confirm_impress_exist = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [764, 494, 765, 496]],
    'en': ["#FFFFFF", "1|0|#FFFFFF", [764, 495, 766, 496]],
}
character_all_boosted = ["#DEDEDE", "1|0|#F0F0F0", [905, 638, 907, 639]]

skills_panel_exist = [["#FFFFFF", "0|1|#FFFFFF", [999, 125, 1000, 127]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 268, 1000, 270]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 411, 1000, 413]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 554, 1000, 556]]]
skills_panel_standby = {
    'tw': ["#6F6F6F", "44|-1|#F0EBE8", [637, 190, 682, 192]],
    'en': ["#6F6F6F", "52|-8|#F0EBE8", [633, 191, 686, 200]],
}
# switch_character_btn_exist = ["#272727", "19|0|#363635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [680, 615, 700, 636]]
# cancel_switch_character_btn_exist = ["#272727", "19|0|#373635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [728, 615, 748, 636]]
switch_character_done = {
    'tw': ["#272727", "19|0|#373635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [728, 615, 748, 636]],     # 取消交替按钮存在，代表交替完成
    'en': ["#F0EBE8", "1|1|#F0EBE8", [783, 20, 785, 22]],       # 检查技能面板上方Front和Back
}

allies_list_btn_exist = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [116, 543, 117, 545]],
    'en': ["#FFFFFF", "0|1|#FFFFFF", [51, 534, 52, 536]],
}
allies_list_opened = {
    'tw': ["#F0EBE8", "1|1|#F0EBE8", [267, 104, 269, 106]],
    'en': ["#F0EBE8", "1|1|#F0EBE8", [260, 102, 262, 104]],
}
# ally_chose = ["#FFFFFF", "1|0|#FFFFFF", [784, 596, 786, 597]]
ally_parting_ways = {
    'tw': ["#FFFFFF", "0|1|#FFFFFF", [785, 481, 786, 483]],
    'en': ["#FFFFFF", "0|1|#FFFFFF", [785, 482, 786, 484]],
}

inn_exist = {
    'b': ["#FFFFFF", "0|1|#FFFFFF", [628, 217, 629, 219]],
    'i’cirlo': ["#FFFFFF", "0|1|#FFFFFF", [628, 217, 629, 219]],
    'c': ["#FFFFFF", "0|1|#FFFFFF", [628, 198, 629, 200]],
    'd': ["#FFFFFF", "0|1|#FFFFFF", [628, 162, 629, 164]],
    'valore': ["#FFFFFF", "0|1|#FFFFFF", [628, 203, 629, 205]],
    'emberglow': ["#FFFFFF", "0|1|#FFFFFF", [628, 167, 629, 169]],
    'theatropolis': ["#FFFFFF", "0|1|#FFFFFF", [628, 246, 629, 248]],
    'rippletide': ["#FFFFFF", "0|1|#FFFFFF", [628, 237, 629, 239]],
    'cragspear': ["#FFFFFF", "0|1|#FFFFFF", [628, 233, 629, 235]],
    'clearbrook': ["#FFFFFF", "0|1|#FFFFFF", [628, 242, 629, 244]],
    'sunshade': ["#FFFFFF", "0|1|#FFFFFF", [628, 238, 629, 240]],
    'shepherds-rock': ["#FFFFFF", "0|1|#FFFFFF", [628, 230, 629, 232]],
}
inn_host_exist = {
    'b': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [805, 244, 819, 263]],
    'i’cirlo': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [805, 244, 819, 263]],
    'c': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [737, 265, 751, 284]],
    'd': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [695, 274, 709, 293]],
    'valore': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [696, 278, 710, 297]],
    'emberglow': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [670, 272, 684, 291]],
    'theatropolis': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [549, 268, 593, 301]],
    'rippletide': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [657, 272, 671, 291]],
    'cragspear': ["#A19E94", "13|-13|#9F9891, 4|5|#575750", [658, 226, 748, 289]],
    'clearbrook': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [745, 271, 759, 290]],
    'sunshade': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [842, 238, 856, 257]],
    'shepherds-rock': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [644, 272, 658, 291]],
}

bt_npc_exist = {
    'bt_axe': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [583, 275, 841, 337]],
    'bt_bow': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [582, 256, 949, 462]],
    'bt_tome': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [630, 220, 740, 330]],
    'bt_spear': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [764, 245, 1056, 344]],
    'bt_dagger': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [362, 206, 873, 544]],
    'bt_staff': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [362, 206, 873, 544]],
    'bt_fan': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [385, 285, 575, 350]],
    'bt_blade': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [500, 265, 860, 320]],
}

bt_ally_exist = {
    # 国际服比台服坐标高24单位
    'bt_axe': ["#492424", "1|1|#B8A994", [334, 215, 336, 241]],
    'bt_bow': ["#5D4B32", "1|1|#E4B98E", [334, 210, 336, 236]],
    'bt_tome': ["#002211", "1|1|#CF7853", [341, 215, 343, 241]],
    'bt_spear': ["#A9947D", "1|1|#EEBB99", [336, 205, 338, 231]],
    'bt_dagger': ["#BB7C60", "1|1|#A5AA88", [339, 207, 341, 233]],
    'bt_staff': ["#BCAD90", "1|1|#646854", [336, 205, 338, 231]],
    'bt_fan': ["#002211", "1|1|#FFEECC", [341, 218, 343, 244]],
    'bt_blade': ["#002211", "1|1|#FFEECC", [341, 218, 343, 244]],
}

enemy_exist = {
    'tikilen': {
        'statement': ["#F0EBE8", "-1|1|#F0EBE8, -2|2|#F0EBE8, -1|3|#F0EBE8, 0|5|#F0EBE8, 1|6|#F0EBE8", [105, 425, 150, 445]],
        'delta': [30, -45],
    },
    'elite-mercenary': {
        'statement': ["#F0EBE8", "0|1|#F0EBE8, 0|2|#F0EBE8, 0|3|#F0EBE8, 1|3|#F0EBE8, 2|3|#F0EBE8, 3|3|#F0EBE8", [270, 510, 325, 525]],
        'delta': [40, -50],
    },
    'veteran-mercenary': {
        'statement': ["#F0EBE8", "1|1|#F0EBE8, 1|2|#F0EBE8, 1|3|#F0EBE8, 2|4|#F0EBE8, 2|5|#F0EBE8, 3|6|#F0EBE8", [430, 385, 480, 405]],
        'delta': [45, -35],
    },
}

skill_boost_level_applied = {
    'tw': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 148, 1266, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 142, 1267, 143]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 137, 1244, 138]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 291, 1266, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 285, 1267, 286]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 280, 1244, 281]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 434, 1266, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 428, 1267, 429]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 423, 1244, 424]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 577, 1266, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 571, 1267, 572]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 566, 1244, 567]],
        },
    ],
    'en': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 148, 1266, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 142, 1267, 143]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 138, 1243, 140]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 291, 1266, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 285, 1267, 286]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 281, 1243, 283]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 434, 1266, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 428, 1267, 429]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 424, 1243, 426]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 577, 1266, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 571, 1267, 572]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 567, 1243, 569]],
        },
    ],
}

attack_boost_level_applied = {
    'tw': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 148, 1264, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 142, 1261, 143]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 145, 1259, 146]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 291, 1264, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 285, 1261, 286]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 288, 1259, 289]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 434, 1264, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 428, 1261, 429]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 431, 1259, 432]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 577, 1264, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 571, 1261, 572]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 574, 1259, 575]],
        },
    ],
    'en': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 148, 1263, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 142, 1261, 143]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 144, 1262, 146]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 291, 1263, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 285, 1261, 286]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 287, 1262, 289]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 434, 1263, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 428, 1261, 429]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 430, 1262, 432]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 577, 1263, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 571, 1261, 572]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 573, 1262, 575]],
        },
    ],
}


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   底层方法部分 - 底层操作，对小派API再封装以实现某些特殊效果。
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def log(text):
    if turn_on_in_game_log:
        xp.log(text)
    if turn_on_console_log:
        xp.console(text)


def wait(t):
    _t = t + 0.2 * stability_mode
    # log("等待：" + str(_t) + "秒")
    sleep(_t)


def tap(x, y):
    _t = 0.05 + 0.02 * stability_mode
    # log("点击：" + str(x) + ", " + str(y))
    xp.tap(x, y, _t)
    sleep(_t + 0.01)


def tap_preset_coord(coord):
    tap(coord[0], coord[1])


def check_statement(statement):
    return xp.findColor(statement[0], statement[1], statement[2][0], statement[2][1], statement[2][2], statement[2][3])


def tap_preset_coord_with_checking(coord, statement, check_per_turn=5, interval=0.10, inverted=False):
    while True:
        tap_preset_coord(coord)
        for i in range(check_per_turn):
            wait(interval)
            if not inverted and check_statement(statement):
                return True
            if inverted and not check_statement(statement):
                return True


def tap_found_coord_with_checking(statement, interval=0.10, dx=0, dy=0):
    while True:
        found_coord = check_statement(statement)
        if found_coord:
            tap(found_coord.x + dx, found_coord.y + dy)
            return
        wait(interval)


def wait_with_checking(statement, max_turns=-1, interval=0.10, inverted=False):
    t = 0
    while True:
        wait(interval)
        t += 1
        if not inverted and check_statement(statement):
            return True
        if inverted and not check_statement(statement):
            return True
        if t == max_turns:
            return False


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   单元模块部分
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def tap_skills_panel(n):
    # 检查技能面板是否开启需要注意，开局时漂浮移动的buff层级最高，会挡住技能面板，导致按键失效或判断错误
    return tap_preset_coord_with_checking(skills_panel_coord[n], battle_idling[region], inverted=True)


def tap_switch_character():
    return tap_preset_coord_with_checking(switch_character_coord[region], switch_character_done[region], interval=0.15)


def tap_skill(boost, x1, y1, x2=0, y2=0):
    # xp.tap(x1, y1, 0.25)
    # sleep(0.18)
    delay = 0.08 if boost == 1 else 0.15 + 0.02 * (boost - 1)
    xp.tap(x1, y1, delay)
    sleep(delay - 0.08)
    if x2 != 0 and y2 != 0:
        tap(x2, y2)


def tap_start_battle():
    return tap_preset_coord_with_checking(start_battle_btn_coord, battle_idling[region], check_per_turn=1, inverted=True)


def tap_flee_battle():
    return tap_preset_coord_with_checking(flee_battle_btn_coord, battle_idling[region], check_per_turn=1, inverted=True)


def tap_until_black_screen(coord):
    return tap_preset_coord_with_checking(coord, black_screen_exist, check_per_turn=1)


def tap_until_minimap_show(coord):
    return tap_preset_coord_with_checking(coord, minimap_exist, check_per_turn=5)


def tap_minimap():
    return tap_preset_coord_with_checking(minimap_coord, menu_exist[region], check_per_turn=1, inverted=True)


def tap_worldmap():
    return tap_preset_coord_with_checking(worldmap_btn_coord[region], menu_opened[region], check_per_turn=2, interval=0.3)


def tap_party():
    return tap_preset_coord_with_checking(party_btn_coord, menu_opened[region], check_per_turn=1, interval=0.2)


def tap_allies_list():
    return tap_preset_coord_with_checking(allies_list_btn_coord, allies_list_opened[region], check_per_turn=1, interval=0.2)


def tap_until_town_menu_opened(coord):
    return tap_preset_coord_with_checking(coord, town_menu_opened[region], check_per_turn=2, interval=0.3)


def tap_worldmap_proceed():
    return tap_preset_coord_with_checking(worldmap_proceed_btn_coord, ok_move_exist[region], check_per_turn=1, interval=0.2)


def tap_bt_npc(npc):
    return tap_found_coord_with_checking(bt_npc_exist[npc], interval=0.2)


def tap_inn_on_main_screen(town):
    return tap_found_coord_with_checking(inn_exist[town], interval=0.2)


def tap_inn_host(town):
    return tap_found_coord_with_checking(inn_host_exist[town], interval=0.2)


def tap_ally(ally):
    return tap_found_coord_with_checking(bt_ally_exist[ally], interval=0.2)


def tap_inquire():
    return tap_preset_coord_with_checking(inquire_btn_coord, inquire_menu_opened, check_per_turn=1, interval=0.2)


def tap_impress():
    return tap_preset_coord_with_checking(impress_btn_coord, confirm_impress_exist[region], check_per_turn=1, interval=0.2)


def tap_part_ways():
    return tap_preset_coord_with_checking(part_ways_btn_coord, ally_parting_ways[region], check_per_turn=1, interval=0.2)


def tap_confirm_part_ways():
    return tap_preset_coord_with_checking(general_ok_btn_coord, ally_parting_ways[region], check_per_turn=1, interval=0.2, inverted=True)


def tap_all_boost():
    return tap_preset_coord_with_checking(all_boost_btn_coord, character_all_boosted, check_per_turn=5, interval=0.1)


def tap_enemy(enemy):
    return tap_found_coord_with_checking(enemy_exist[enemy]['statement'], dx=enemy_exist[enemy]['delta'][0], dy=enemy_exist[enemy]['delta'][1])


def wait_skills_panel_shown():
    return wait_with_checking(skills_panel_standby[region], max_turns=10)


def wait_skills_panel_gone():
    return wait_with_checking(skills_panel_standby[region], max_turns=20, interval=0.05, inverted=True)


def wait_inquire_shown():
    return wait_with_checking(inquire_exist, max_turns=25, interval=0.2)


def wait_battle_idling(interval=0.5):
    return wait_with_checking(battle_idling[region], interval=interval)


def wait_black_screen_start():
    return wait_with_checking(black_screen_exist, interval=0.5)


def wait_black_screen_end():
    return wait_with_checking(black_screen_exist, interval=0.5, inverted=True)


def wait_main_screen_idling():
    return wait_with_checking(menu_exist[region], interval=0.2)


def wait_main_screen_idling_end():
    return wait_with_checking(menu_exist[region], interval=0.2, inverted=True)


def wait_minimap_disappear():
    return wait_with_checking(minimap_exist, interval=0.2, inverted=True)


def wait_allies_list_btn_shown():
    return wait_with_checking(allies_list_btn_exist[region], interval=0.2)


# def wait_bt_ally(ally):
#     return wait_with_checking(bt_ally_exist[ally], interval=0.2)


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   复合模块部分
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def open_skills_panel(n):
    count = 0
    while True:
        if count > 0:
            log("【注意】：技能面板没有打开，重试")
        tap_skills_panel(n)
        count += 1
        if wait_skills_panel_shown():
            return


def await_black_screen_transition():
    wait_black_screen_start()
    wait_black_screen_end()


def open_minimap():
    wait_main_screen_idling()
    tap_minimap()


def open_worldmap():
    wait_main_screen_idling()
    tap_worldmap()


def open_party():
    wait_main_screen_idling()
    tap_party()


def open_allies_list():
    wait_allies_list_btn_shown()
    tap_allies_list()


def part_ways_ally(ally):
    # wait_bt_ally(ally)
    #   这里点击支援者如果失效，改成带检查重复点击的设计
    tap_ally(ally)
    tap_part_ways()
    tap_confirm_part_ways()
    tap_until_minimap_show(close_menu_btn_coord)


def move_using_minimap(coord):
    open_minimap()
    wait(0.3)
    tap_preset_coord(coord)


def move_using_worldmap(coord):
    open_worldmap()
    wait(0.5)
    tap_until_town_menu_opened(coord)
    tap_worldmap_proceed()
    tap_until_black_screen(general_ok_btn_coord)


#   -------------------------------------------------------------------------------------------------
# def use_skill(n, boost=1):
#     skill_coord = skills_coord[n][boost-1]
#     while True:
#         tap_skill(boost, skill_coord[0], skill_coord[1], skill_coord[2], skill_coord[3])
#         if wait_skills_panel_gone():
#             return
#   -------------------------------------------------------------------------------------------------
def use_skill(n, boost=1, t=0):
    if n == 5:
        tap(705, 93)
        wait(0.5)
        tap(923, 399)
        if wait_battle_idling():
            return
    skill_coord = skills_coord[region][n][boost - 1]
    count = 0
    while True:
        if count > 0:
            log("【注意】：重复点击技能")
        tap_skill(boost, skill_coord[0], skill_coord[1], skill_coord[2], skill_coord[3])
        if t != 0:
            wait(0.2)
            tap(skills_panel_coord[t-1][0], skills_panel_coord[t-1][1])
            wait(0.2)
        count += 1
        if wait_skills_panel_gone():
            return


def inquire_and_impress_bt_npc(npc):
    while True:
        tap_bt_npc(npc)
        if wait_inquire_shown():
            break
    tap_inquire()
    tap_impress()
    tap_until_black_screen(lower_ok_btn_coord)


def recover_in_inn(town):
    wait_main_screen_idling()
    #   这里点击旅店老板有概率失效，如果失效，改成带检查重复点击的设计
    tap_inn_host(town)
    wait_minimap_disappear()
    tap_until_black_screen(lower_ok_btn_coord)
    await_black_screen_transition()
    tap_until_minimap_show(center_ok_btn_coord)


def flee_battle():
    wait_battle_idling()
    tap_flee_battle()


def run_preset_character_action(n, action, retry=False):
    switch_character = action[0] > 9
    skill_to_use = action[0] % 10 if action[0] != -1 else -1
    boost_level = action[1]
    target_character = action[2]
    target_enemy = action[3]
    require_checking = False if boost_level == 1 else True

    if skill_to_use == -1:
        return
    open_skills_panel(n)

    if target_enemy != 0 and not retry:
        wait(0.2)
        tap_enemy(target_enemy)
        wait(0.2)

    if switch_character and not retry:
        tap_switch_character()
        # 国际服 - 切换完角色之后不做检查的话，会在瞬间完成以下动作：
        # 1.点击技能（但是面板未就绪，技能没有点上）
        # 2.检查技能面板解除（由于技能面板尚未显示，因此检查会通过）
        # 3.点击下一位角色的技能面板（由于上一位角色面板未消失，因此通过）
        # 4.点击下一位角色的技能（但是点成了上一位的）
        # 原因：因为台服检查的是底部的取消交替按钮，这个按钮的UI是最后出现的，因此检查到了必定切换完成且就绪，但是国际服检查的是顶部Front/Back，检查到的时候不一定就绪。
        if region == "en":
            wait_skills_panel_shown()
    use_skill(skill_to_use, boost_level, target_character)

    if not require_checking:
        return
    boost_level_applied = attack_boost_level_applied[region] if skill_to_use == 0 else skill_boost_level_applied[region]
    boost_level_check_result = wait_with_checking(boost_level_applied[n][str(boost_level)], max_turns=10)
    if not boost_level_check_result:
        log("【注意】：角色boost等级错误，重新使用技能")
        run_preset_character_action(n, action, retry=True)


def run_preset_turn_sequence(turn):
    all_boost = turn['all_boost']
    skill_list = turn['skill_list']

    wait_battle_idling()
    for n, character_action in enumerate(skill_list):
        character_action[1] = 1 if all_boost else character_action[1]
        run_preset_character_action(n, character_action)
    wait_battle_idling(0.1)
    tap_all_boost() if all_boost else None
    tap_start_battle()


def run_preset_battle_sequence(sequence_list):
    for i, sequence in enumerate(sequence_list):
        # log("开始第" + str(i+1) + "回合")
        run_preset_turn_sequence(sequence)
    tap_until_black_screen(screen_center_coord)


def move_towards_bt_npc(npc):
    if npc == 'bt_axe':
        move_using_minimap(valore_main_boulevard_coord)
        wait(8)
        await_black_screen_transition()
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(5)
    elif npc == 'bt_bow':
        # 方法1：通过小地图
        # move_using_minimap(emberglow_east_district_coord)
        # wait(15)
        # await_black_screen_transition()
        # move_using_minimap(bt_npc_coord_on_minimap[npc])
        # wait(12)
        # 方法2：通过大地图
        move_using_worldmap(emberglow_laboratory_coord)
        await_black_screen_transition()
        move_using_minimap(emberglow_laboratory_to_town_coord)
        await_black_screen_transition()
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(8)
    elif npc == 'bt_tome':
        move_using_minimap(theatropolis_library_coord)
        wait(15)
        await_black_screen_transition()
    elif npc == 'bt_spear':
        move_using_minimap(rippletide_residence_coord)
        wait(7)
        await_black_screen_transition()
    elif npc == 'bt_dagger':
        move_using_minimap(cragspear_slums_coord)
        wait(17)
        await_black_screen_transition()
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(9)
    elif npc == 'bt_staff':
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(5)
    elif npc == 'bt_fan':
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(6)
    elif npc == 'bt_blade':
        move_using_minimap(bt_npc_coord_on_minimap[npc])
        wait(6)


def run_script():
    total_count = 0
    while True:
        total_count += 1
        xp.log("第" + str(total_count) + "轮")
        start_time = time()

        # 战斗前
        move_towards_bt_npc(targeting_npc)

        for i in range(round_per_recover):
            inquire_and_impress_bt_npc(targeting_npc)
            await_black_screen_transition()

            # 战斗中
            xp.log("第" + str(i+1) + "场")
            # flee_battle()
            run_preset_battle_sequence(battle_sequence)
            tap_until_minimap_show(close_menu_btn_coord)

            # 战斗后
            open_party()
            open_allies_list()
            part_ways_ally(targeting_npc)

        move_using_worldmap(screen_center_coord)
        await_black_screen_transition()
        tap_inn_on_main_screen(get_town_name_by_npc[targeting_npc])
        await_black_screen_transition()
        recover_in_inn(get_town_name_by_npc[targeting_npc])
        move_using_minimap(inn_exit_coord[get_town_name_by_npc[targeting_npc]])
        await_black_screen_transition()

        xp.log("本轮用时：" + str(int(time() - start_time)) + "秒")
        log("------------------------")


memories_read_btn_coord = [1104, 507]
memories_ok_btn_coord = [700, 530]
memories_confirm_read = ["#FFFFFF", "1|0|#FFFFFF", [782, 590, 784, 591]]
memories_read_exist = ["#FFFFFF", "1|0|#FFFFFF", [1082, 498, 1084, 499]]


def tap_memories_read():
    return tap_preset_coord_with_checking(memories_read_btn_coord, memories_confirm_read, check_per_turn=1)


def tap_memories_ok_after_battle():
    return tap_preset_coord_with_checking(memories_ok_btn_coord, memories_read_exist, check_per_turn=1)


def moving():
    xp.swipe(1200, 700, 1000, 700)
    wait(0.5)
    xp.swipe(1000, 700, 1200, 700)
    wait(0.5)


def is_battle():
    ret = xp.matchColor("#FFFFFF", 1082, 643)
    if ret:
        return True
    else:
        return False


def find_lv55_cat():
    ret = xp.findColor("#C6B45B", "0|1|#7C520C", 156, 52, 157, 54)
    if ret:
        # xp.console("找到猫")
        return True
    else:
        # xp.console("不是猫")
        return False


def find_lv50_cat():
    ret = xp.findColor("#EEDFAF", "1|1|#6E5E33, -1|-1|#EEDFAF", 143, 72, 147, 76)
    if ret:
        return True
    else:
        return False


while True:
    count = 0
    req_init = True
    while True:
        if count == 0 and req_init:
            open_minimap()
            wait(0.5)
            xp.tap(569, 177)
            wait(5)
            req_init = False
        if count == 8:
            break
        moving()
        if is_battle() is True:
            # print("start battle")
            sleep(0.5)
            if find_lv55_cat() is True:
                # log("cait 1")
                # cait_battle_sequence()
                # break
                xp.tap(540, 643)
                wait(1)
            elif find_lv50_cat() is True:
                # log("cait 2")
                xp.tap(540, 643)
                wait(1)
            else:
                # print("normal battle")
                run_preset_battle_sequence(battle_sequence)
                tap_until_black_screen(screen_center_coord)
                wait_main_screen_idling()
                count += 1
        else:
            continue

    move_using_worldmap([395, 273])
    await_black_screen_transition()
    tap_inn_on_main_screen("i’cirlo")
    await_black_screen_transition()
    recover_in_inn('i’cirlo')
    move_using_worldmap([888, 455])
    await_black_screen_transition()


# from time import *
# from PyGameAutoAndroid import *
#
# #   -------------------------------------------------------------------------------------------------
# #   使用者参数部分 - 通过调整参数改变脚本功能
# #   -------------------------------------------------------------------------------------------------
# #   targeting_npc - 配置脚本目标为哪位历战NPC
# #       可选值: 'bt_axe'    - 历战斧 - 瓦洛雷
# #              'bt_bow'    - 历战弓 - 恩波格洛
# #              'bt_tome'   - 历战书 - 希亚特珀利斯
# #              'bt_spear'  - 历战枪 - 利布尔泰德
# #              'bt_dagger' - 历战匕 - 克拉古斯比亚
# #              'bt_staff'  - 历战杖 - 库利亚布鲁克
# #              'bt_fan'    - 历战扇 - 桑谢德
# #              'bt_sword'  - 历战剑 - 利布尔泰德
#
# targeting_npc = "bt_tome"
#
# #   battle_sequence - 预设战斗序列 - 此设计为临时方案
# #                     由于每位玩家拥有的角色，技能，星级均不同，技能位置，队伍组成也不同，因此这段必须自己设计并提供数值
# #                     此参数为三维数组：
# #                           第1维为战斗回合层，第一维数组有多少元素就有多少战斗回合
# #                           第2维为回合内角色层，只有4个元素，分别代表从上到下第1234位角色
# #                           第3维为角色技能层，只有2个元素，第一个元素为使用哪个技能，第二个元素为使用几级Boost
# #                           关于技能，可选值为-1, 0, 1, 2, 3, 10, 11, 12, 13
# #                               -1 - 跳过本角色
# #                               0  - 使用普攻
# #                               1  - 使用第一个技能
# #                               2  - 使用第二个技能
# #                               3  - 使用第三个技能
# #                               10 - 交换角色，使用普攻
# #                               11 - 交换角色，使用第一个技能
# #                               12 - 交换角色，使用第二个技能
# #                               13 - 交换角色，使用第三个技能
# #                           关于Boost，可选值为1, 2, 3, 4
# #                               1  - 无Boost
# #                               2  - 2级Boost
# #                               3  - 3级Boost
# #                               4  - 满级Boost
#
# battle_sequence = [
#     # 第1回合
#     [[3, 1],   # 第1位角色交换，使用第2个技能，无Boost
#      [-1, 1],    # 第2位角色，使用第1个技能，无Boost
#      [-1, 1],
#      [-1, 1]],
#     # 第n回合 - 如有需求可以一直加下去，但要保证你的战斗流程每次都相同，不可以这次战斗4回合，下次战斗5回合
# ]
#
# #   -------------------------------------------------------------------------------------------------
# #                               ※如果不懂编程或看不懂代码，从这里往下可以不用看了※
# #   -------------------------------------------------------------------------------------------------
# #   开发者参数部分 - 通过调整参数改变脚本性能
# stability_mode = 0
# turn_on_in_game_log = False
# turn_on_console_log = True
#
# cragspear_slums_coord = [841, 616]
# theatropolis_library_coord = [447, 416]
#
# #   常数部分 - 游戏内固定参数，比如地图按钮的位置。
# #   当更换设备时，由于屏幕分辨率发生变化，这些数值都会失效，放在这里统一更改，比去代码里寻找效率更高。
# #   单点坐标常数
# screen_center_coord = [640, 360]  # 屏幕正中
# minimap_coord = [1078, 137]  # 主界面 - 小地图上箭头坐标
# party_btn_coord = [215, 605]  # 主界面 - 大陆地图按钮坐标
# worldmap_btn_coord = [468, 605]  # 主界面 - 队伍按钮坐标
# allies_list_btn_coord = [116, 543]  # 队伍界面 - 支援者列表按钮坐标
# first_ally_coord = [387, 256]  # 支援者列表 - 第一位支援者位置坐标
# part_ways_btn_coord = [796, 597]  # 支援者列表 - 告别按钮位置
# general_ok_btn_coord = [800, 480]  # 菜单界面 - 通用OK按钮坐标，如：确认告别的OK按钮，确认大地图前往某处的是按钮
# close_menu_btn_coord = [1236, 22]  # 菜单界面 - 右上角叉按钮位置
# inquire_btn_coord = [1176, 626]  # 主界面 - 打听按钮位置
# impress_btn_coord = [1043, 400]  # 打听界面 - 收服按钮位置
# confirm_impress_btn_coord = [763, 500]  # 收服界面 - 收服按钮位置
# lower_ok_btn_coord = [800, 514]  # 菜单界面 - 低位OK按钮坐标，如：确认收服OK按钮，确认住店按钮
# center_ok_btn_coord = [642, 480]  # 菜单界面 - 中间OK按钮坐标
# worldmap_proceed_btn_coord = [1051, 641]  # 世界地图 - 前往这里按钮位置
# skills_panel_coord = [[1150, 90],
#                       [1150, 230],
#                       [1150, 370],
#                       [1150, 520]]
# switch_character_coord = [793, 626]
# skills_coord = [[[850, 200, 0, 0],
#                  [850, 200, 1025, 170],
#                  [850, 200, 1115, 170],
#                  [850, 200, 1200, 170]],
#                 [[850, 305, 0, 0],
#                  [850, 305, 1025, 290],
#                  [850, 305, 1115, 290],
#                  [850, 305, 1200, 290]],
#                 [[850, 410, 0, 0],
#                  [850, 410, 1025, 400],
#                  [850, 410, 1115, 400],
#                  [850, 410, 1200, 400]],
#                 [[850, 525, 0, 0],
#                  [850, 525, 1025, 520],
#                  [850, 525, 1115, 520],
#                  [850, 525, 1200, 520]]]
# start_battle_btn_coord = [1083, 643]
#
# inn_exit_coord = {
#     'theatropolis': [645, 447],
#     'cragspear': [526, 448],
# }
#
# get_town_name_by_npc = {
#     'bt_tome': 'theatropolis',
#     'bt_dagger': 'cragspear',
# }
#
# bt_npc_coord_on_minimap = {
#     'bt_tome': [0, 0],
#     'bt_dagger': [727, 535],
# }
#
# #   多点找色常数
# minimap_exist = ["#E2D57E", "1|0|#E2D57E", [1078, 137, 1080, 138]]
# menu_exist = ["#B2B2B2", "1|1|#DFDEDE", [961, 595, 963, 597]]  # 使用了探索按钮右上角的白色星做判断，如果没有导石UP的情况下可能失效
# menu_opened = ["#E9E9E9", "1|1|#E9E9E9", [1235, 19, 1237, 21]]
# character_standby = ["#F0EBE8", "1|0|#F0EBE8", [681, 168, 683, 169]]
# # battle_idling = ["#FFFFFF", "1|1|#FFFFFF", [1082, 642, 1084, 644]]
# battle_idling = ["#FFFFFF", "1|1|#FFFFFF", [1038, 629, 1040, 631]]
# black_screen_exist = ["#000000", "1|1|#000000", [639, 359, 641, 361]]
# town_menu_opened = ["#FFFFFF", "0|1|#FFFFFF", [1001, 635, 1002, 637]]
# # ok_move_exist = ["#FFFFFF", "0|1|#FFFFFF", [783, 432, 785, 434]]
# ok_move_exist = ["#FFFFFF", "0|1|#FFFFFF", [783, 479, 785, 481]]
# inquire_exist = ["#62AAAA", "0|1|#5C6F6F", [1076, 656, 1096, 658]]
# inquire_menu_opened = ["#58BBB0", "1|1|#58BBB0", [1150, 279, 1158, 281]]
# confirm_impress_exist = ["#FFFFFF", "0|1|#FFFFFF", [764, 494, 765, 496]]
#
# skills_panel_exist = [["#FFFFFF", "0|1|#FFFFFF", [999, 125, 1000, 127]],
#                       ["#FFFFFF", "0|1|#FFFFFF", [999, 268, 1000, 270]],
#                       ["#FFFFFF", "0|1|#FFFFFF", [999, 411, 1000, 413]],
#                       ["#FFFFFF", "0|1|#FFFFFF", [999, 554, 1000, 556]]]
# # skills_panel_standby = ["#F0EBE8", "-48|9|#6F6F6F", [633, 168, 682, 178]]
# skills_panel_standby = {
#     'tw': ["#F0EBE8", "-48|9|#6F6F6F", [633, 168, 682, 178]],
#     'en': ["#6F6F6F", "52|-8|#F0EBE8", [633, 191, 686, 200]],
# }
# switch_character_btn_exist = ["#272727", "19|0|#363635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [680, 615, 700, 636]]
# cancel_switch_character_btn_exist = ["#272727", "19|0|#373635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [728, 615, 748, 636]]
#
# allies_list_btn_exist = ["#FFFFFF", "0|1|#FFFFFF", [116, 543, 117, 545]]
# allies_list_opened = ["#F0EBE8", "1|1|#F0EBE8", [267, 104, 269, 106]]
# # ally_chose = ["#FFFFFF", "1|0|#FFFFFF", [784, 596, 786, 597]]
# ally_parting_ways = ["#FFFFFF", "0|1|#FFFFFF", [785, 481, 786, 483]]
#
# inn_exist = {
#     'a': ["#FFFFFF", "0|1|#FFFFFF", [628, 167, 629, 169]],
#     'b': ["#FFFFFF", "0|1|#FFFFFF", [628, 217, 629, 219]],
#     'theatropolis': ["#FFFFFF", "0|1|#FFFFFF", [628, 246, 629, 248]],
#     'cragspear': ["#FFFFFF", "0|1|#FFFFFF", [628, 233, 629, 235]],
# }
# inn_host_exist = {
#     'a': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [670, 272, 684, 291]],
#     'b': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [805, 244, 819, 263]],
#     'theatropolis': ["#A19E94", "13|-13|#9F9891, 4|5|#54544E", [549, 268, 593, 301]],
#     'cragspear': ["#A19E94", "13|-13|#9F9891, 4|5|#575750", [658, 226, 748, 289]],
# }
#
# bt_npc_exist = {
#     'bt_tome': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [640, 219, 719, 281]],
#     'bt_dagger': ["#D59590", "1|1|#D28F8A, 2|2|#D98882", [362, 206, 873, 544]],
# }
#
# bt_ally_exist = {
#     'bt_tome': ["#002211", "1|1|#CF7853", [341, 239, 343, 241]],
#     'bt_spear': ["#A9947D", "1|1|#EEBB99", [336, 229, 338, 231]],
#     'bt_dagger': ["#BB7C60", "1|1|#A5AA88", [339, 231, 341, 233]],
# }
#
# boost_level_applied = [
#     {
#         '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 148, 1266, 149]],
#         '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 142, 1267, 143]],
#         '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 137, 1244, 138]],
#     },
#     {
#         '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 291, 1266, 292]],
#         '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 285, 1267, 286]],
#         '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 280, 1244, 281]],
#     },
#     {
#         '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 434, 1266, 435]],
#         '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 428, 1267, 429]],
#         '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 423, 1244, 424]],
#     },
#     {
#         '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 577, 1266, 578]],
#         '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 571, 1267, 572]],
#         '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 566, 1244, 567]],
#     },
# ]
#
#
# #   -------------------------------------------------------------------------------------------------
# #   -------------------------------------------------------------------------------------------------
# #   底层方法部分 - 底层操作，对小派API再封装以实现某些特殊效果。
# #   -------------------------------------------------------------------------------------------------
# #   -------------------------------------------------------------------------------------------------
# def log(text):
#     if turn_on_in_game_log:
#         xp.log(text)
#     if turn_on_console_log:
#         xp.console(text)
#
#
# def wait(t):
#     _t = t + 0.2 * stability_mode
#     # log("等待：" + str(_t) + "秒")
#     sleep(_t)
#
#
# def tap(x, y):
#     _t = 0.05 + 0.02 * stability_mode
#     # log("点击：" + str(x) + ", " + str(y))
#     xp.tap(x, y, _t)
#     sleep(_t + 0.01)
#
#
# def tap_preset_coord(coord):
#     tap(coord[0], coord[1])
#
#
# def check_statement(statement):
#     return xp.findColor(statement[0], statement[1], statement[2][0], statement[2][1], statement[2][2], statement[2][3])
#
#
# def tap_preset_coord_with_checking(coord, statement, check_per_turn=5, interval=0.10, inverted=False):
#     while True:
#         tap_preset_coord(coord)
#         for i in range(check_per_turn):
#             wait(interval)
#             if not inverted and check_statement(statement):
#                 return True
#             if inverted and not check_statement(statement):
#                 return True
#
#
# def tap_found_coord_with_checking(statement, interval=0.10):
#     while True:
#         found_coord = check_statement(statement)
#         if found_coord:
#             tap(found_coord.x, found_coord.y)
#             return
#         wait(interval)
#
#
# def wait_with_checking(statement, max_turns=-1, interval=0.10, inverted=False):
#     t = 0
#     while True:
#         wait(interval)
#         t += 1
#         if not inverted and check_statement(statement):
#             return True
#         if inverted and not check_statement(statement):
#             return True
#         if t == max_turns:
#             return False
#
#
# def find_lv55_cat():
#     ret = xp.findColor("#2930DB", "1|1|#4E4F50, -1|-1|#091137", 142, 81, 146, 85)
#     if ret:
#         # xp.console("找到猫")
#         return True
#     else:
#         # xp.console("不是猫")
#         return False
#
#
# def find_lv50_cat():
#     ret = xp.findColor("#EEDFAF", "1|1|#6E5E33, -1|-1|#EEDFAF", 143, 72, 147, 76)
#     if ret:
#         return True
#     else:
#         return False
#
#
# def find_battle_wolf():
#     ret = xp.findColor("#FF7272", "-1|0|#6E9E9E", 119, 32, 459, 101)
#     if ret:
#         return True
#     else:
#         return False
#
#
# def check_minimap():
#     ret = xp.findColor("#E2D57E", "1|0|#E2D57E", 1078, 137, 1080, 138)
#     if ret:
#         return True
#     else:
#         return False
#
#
# def is_map_opened():
#     ret = xp.matchColor("#E9E9E9", 1236, 20)
#     if ret:
#         log("?")
#         return True
#     else:
#         log("??")
#         return False
#
#
# def is_town_menu_opened():
#     ret = xp.matchColor("#255971", 982, 643)
#     if ret:
#         return True
#     else:
#         return False
#
#
# def open_minimap():
#     while True:
#         if check_minimap():
#             break
#         else:
#             sleep(0.2)
#     while True:
#         if is_map_opened():
#             break
#         else:
#             xp.tap(1078, 137)
#             sleep(0.2)
#
#
# def open_worldmap():
#     while True:
#         if check_minimap():
#             break
#         else:
#             sleep(0.2)
#     while True:
#         if is_map_opened():
#             break
#         else:
#             xp.tap(732, 607)
#             sleep(0.5)
#
#
# def heal(x, y):
#     while True:
#         if check_minimap():
#             break
#         else:
#             sleep(0.2)
#     xp.tap(x, y)
#     sleep(0.5)
#
#
# def goto_wild():
#     while True:
#         if check_minimap():
#             break
#         else:
#             sleep(0.2)
#     find_color_click("#FFFFFF", 120, 138)
#     find_color_click("#000000", 108, 333)
#
#
# def goto_town(tx, ty):
#     while True:
#         if is_town_menu_opened():
#             break
#         else:
#             xp.tap(tx, ty)
#             sleep(1.2)
#     find_color_click("#2D637B", 1053, 657)
#     find_color_click("#2D6279", 797, 496)
#
#
# def find_color_click(color, x, y, cx=None, cy=None):
#     if cx is None:
#         cx = x
#     if cy is None:
#         cy = y
#     while True:
#         ret = xp.matchColor(color, x, y)
#         if not ret:
#             wait(0.1)
#             continue
#         wait(0.3)
#         xp.tap(cx, cy, 0.1)
#         break
#
#
# def find_no_color_click(color, x, y, cx=None, cy=None):
#     if cx is None:
#         cx = x
#     if cy is None:
#         cy = y
#     while True:
#         ret = xp.matchColor(color, x, y)
#         if ret:
#             wait(0.1)
#             continue
#         wait(0.3)
#         xp.tap(cx, cy)
#         break
#
#
# def goto_town_old():
#     # xp.console("尝试进城")
#     find_color_click("#BBB652", 640, 364, cx=821, cy=198)
#     find_color_click("#2D637B", 1053, 657)
#     find_color_click("#2D6279", 797, 496)
#
#
# def heal_self():
#     # xp.console("尝试回血")
#     find_color_click("#FFFFFF", 643, 203)
#     find_color_click("#000000", 643, 203)
#     # xp.console("1")
#     heal(698, 262)
#     # xp.console("2")
#     find_color_click("#D0C4B4", 441, 144)
#     while True:
#         ret = xp.matchColor("#E2D57E", 1081, 137)
#         if ret:
#             wait(1)
#             xp.tap(471, 611)
#             break
#         else:
#             wait(0.1)
#             xp.tap(796, 506)
#             continue
#     # xp.console("尝试去野外")
#     find_color_click("#E9E9E9", 1236, 21, cx=834, cy=422)
#     find_color_click("#2D637B", 1052, 659)
#     find_color_click("#2C627B", 797, 498)
#
#
# def moving():
#     xp.swipe(1200, 700, 1000, 700)
#     wait(0.5)
#     xp.swipe(1000, 700, 1200, 700)
#     wait(0.5)
#
#
# def is_battle():
#     ret = xp.matchColor("#FFFFFF", 1039, 650)
#     if ret:
#         return True
#     else:
#         return False
#
#
# def cait_battle_sequence():
#     while True:
#         ret = xp.matchColor("#000000", 756, 357)
#         if not ret:
#             wait(2)
#             # xp.tap(756, 357)
#             continue
#         break
#
#
# # def battle_sequence():
# #     find_color_click("#548654", 1074, 79)
# #     wait(0.3)
# #     find_color_click("#6F6F6F", 919, 564, cx=714, cy=516)
# #     wait(0.5)
# #     # if find_battle_wolf() is True:
# #     # find_color_click("#548654", 1069, 221)
# #     # wait(0.3)
# #     # find_color_click("#6F6F6F", 919, 564, cx=714, cy=516)
# #     # wait(0.5)
# #     find_color_click("#FFFFFF", 1083, 643, cx=864, cy=643)
# #     find_color_click("#FFFFFF", 1083, 643)
# #
# #     while True:
# #         ret = xp.matchColor("#000000", 756, 357)
# #         if not ret:
# #             wait(0.1)
# #             xp.tap(756, 357)
# #             continue
# #         break
# #   -------------------------------------------------------------------------------------------------
# #   -------------------------------------------------------------------------------------------------
# #   单元模块部分
# #   -------------------------------------------------------------------------------------------------
# #   -------------------------------------------------------------------------------------------------
# def tap_skills_panel(n):
#     return tap_preset_coord_with_checking(skills_panel_coord[n - 1], skills_panel_exist[n - 1], check_per_turn=2)
#
#
# def tap_switch_character():
#     return tap_preset_coord_with_checking(switch_character_coord, cancel_switch_character_btn_exist, interval=0.15)
#
#
# def tap_skill(boost, x1, y1, x2=0, y2=0):
#     # xp.tap(x1, y1, 0.25)
#     # sleep(0.18)
#     delay = 0.20 + 0.02 * (boost - 1)
#     xp.tap(x1, y1, delay)
#     sleep(delay - 0.08)
#     if x2 != 0 and y2 != 0:
#         tap(x2, y2)
#
#
# def tap_start_battle():
#     return tap_preset_coord_with_checking(start_battle_btn_coord, battle_idling, check_per_turn=1, inverted=True)
#
#
# def tap_until_black_screen(coord):
#     return tap_preset_coord_with_checking(coord, black_screen_exist, check_per_turn=1)
#
#
# def tap_until_minimap_show(coord):
#     return tap_preset_coord_with_checking(coord, minimap_exist, check_per_turn=1)
#
#
# def tap_minimap():
#     return tap_preset_coord_with_checking(minimap_coord, menu_exist, check_per_turn=1, inverted=True)
#
#
# def tap_worldmap():
#     return tap_preset_coord_with_checking(worldmap_btn_coord, menu_opened, check_per_turn=2, interval=0.3)
#
#
# def tap_party():
#     return tap_preset_coord_with_checking(party_btn_coord, menu_opened, check_per_turn=1, interval=0.2)
#
#
# def tap_allies_list():
#     return tap_preset_coord_with_checking(allies_list_btn_coord, allies_list_opened, check_per_turn=1, interval=0.2)
#
#
# def tap_until_town_menu_opened(coord):
#     return tap_preset_coord_with_checking(coord, town_menu_opened, check_per_turn=2, interval=0.3)
#
#
# def tap_worldmap_proceed():
#     return tap_preset_coord_with_checking(worldmap_proceed_btn_coord, ok_move_exist, check_per_turn=1, interval=0.2)
#
#
# def tap_bt_npc(npc):
#     return tap_found_coord_with_checking(bt_npc_exist[npc], interval=0.2)
#
#
# def tap_inn_on_main_screen(town):
#     return tap_found_coord_with_checking(inn_exist[town], interval=0.2)
#
#
# def tap_inn_host(town):
#     return tap_found_coord_with_checking(inn_host_exist[town], interval=0.2)
#
#
# def tap_ally(ally):
#     return tap_found_coord_with_checking(bt_ally_exist[ally], interval=0.2)
#
#
# def tap_inquire():
#     return tap_preset_coord_with_checking(inquire_btn_coord, inquire_menu_opened, check_per_turn=1, interval=0.2)
#
#
# def tap_impress():
#     return tap_preset_coord_with_checking(impress_btn_coord, confirm_impress_exist, check_per_turn=1, interval=0.2)
#
#
# def tap_part_ways():
#     return tap_preset_coord_with_checking(part_ways_btn_coord, ally_parting_ways, check_per_turn=1, interval=0.2)
#
#
# def tap_confirm_part_ways():
#     return tap_preset_coord_with_checking(general_ok_btn_coord, ally_parting_ways, check_per_turn=1, interval=0.2, inverted=True)
#
#
# def wait_skills_panel_shown():
#     return wait_with_checking(skills_panel_standby['en'], max_turns=20)
#
#
# def wait_skills_panel_gone():
#     return wait_with_checking(skills_panel_standby['en'], max_turns=20, interval=0.05, inverted=True)
#
# def wait_inquire_shown():
#     return wait_with_checking(inquire_exist, max_turns=20, interval=0.2)
#
#
# def wait_battle_idling(interval=0.5):
#     return wait_with_checking(battle_idling, interval=interval)
#
#
# def wait_black_screen_start():
#     return wait_with_checking(black_screen_exist, interval=0.5)
#
#
# def wait_black_screen_end():
#     return wait_with_checking(black_screen_exist, interval=0.5, inverted=True)
#
#
# def wait_main_screen_idling():
#     return wait_with_checking(menu_exist, interval=0.2)
#
#
# def wait_main_screen_idling_end():
#     return wait_with_checking(menu_exist, interval=0.2, inverted=True)
#
#
# def wait_minimap_disappear():
#     return wait_with_checking(minimap_exist, interval=0.2, inverted=True)
#
#
# def wait_allies_list_btn_shown():
#     return wait_with_checking(allies_list_btn_exist, interval=0.2)
#
#
# def open_skills_panel(n):
#     count = 0
#     while True:
#         if count > 0:
#             log("【注意】：技能面板没有打开，重试")
#         tap_skills_panel(n)
#         count += 1
#         if wait_skills_panel_shown():
#             return
#
# def use_skill(n, boost=1):
#     skill_coord = skills_coord[n][boost - 1]
#     count = 0
#     while True:
#         if count > 0:
#             log("【注意】：重复点击技能")
#         tap_skill(boost, skill_coord[0], skill_coord[1], skill_coord[2], skill_coord[3])
#         count += 1
#         if wait_skills_panel_gone():
#             return
#
# def check_boost_level(sequence):
#     for n, character_movement in enumerate(sequence):
#         skill_to_use = character_movement[0]
#         boost_level = character_movement[1]
#         if boost_level != 1:
#             boost_level_check_result = check_statement(boost_level_applied[n][str(boost_level)])
#             if not boost_level_check_result:
#                 log("【注意】：角色boost等级错误，重新使用技能")
#                 if skill_to_use != -1:
#                     open_skills_panel(n + 1)
#                     if skill_to_use > 9:
#                         tap_switch_character()
#                         skill_to_use -= 10
#                     use_skill(skill_to_use, boost_level)
#                     wait_battle_idling(0.1)
#
# def move_using_worldmap(coord):
#     open_worldmap()
#     sleep(0.5)
#     log("1")
#     tap_until_town_menu_opened(coord)
#     log("2")
#     tap_worldmap_proceed()
#     tap_until_black_screen(general_ok_btn_coord)
#
#
# def run_preset_battle_sequence(sequence_list):
#     log("1")
#     for i, sequence in enumerate(sequence_list):
#         wait_battle_idling()
#         log("开始第" + str(i+1) + "回合")
#         for j, character_movement in enumerate(sequence):
#             skill_to_use = character_movement[0]
#             boost_level = character_movement[1]
#             if skill_to_use != -1:
#                 open_skills_panel(j + 1)
#                 if skill_to_use > 9:
#                     tap_switch_character()
#                     skill_to_use -= 10
#                 use_skill(skill_to_use, boost_level)
#         wait_battle_idling(0.1)
#         check_boost_level(sequence)
#         tap_start_battle()
#
# def await_black_screen_transition():
#     wait_black_screen_start()
#     wait_black_screen_end()
#
# def move_using_minimap(coord):
#     open_minimap()
#     sleep(0.2)
#     tap_preset_coord(coord)
#
#
# def recover_in_inn(town):
#     wait_main_screen_idling()
#     #   这里点击旅店老板有概率失效，如果失效，改成带检查重复点击的设计
#     tap_inn_host(town)
#     wait_minimap_disappear()
#     tap_until_black_screen(lower_ok_btn_coord)
#     await_black_screen_transition()
#     tap_until_minimap_show(center_ok_btn_coord)
#
#
# while True:
#     count = 0
#     req_init = True
#     while True:
#         if count == 0 and req_init:
#             open_minimap()
#             wait(1)
#             xp.tap(381, 576)
#             wait(2)
#             req_init = False
#         if count == 9:
#             break
#         moving()
#         if is_battle() is True:
#             # log("start battle")
#             sleep(0.5)
#             if find_lv55_cat() is True:
#                 # log("cait 1")
#                 # cait_battle_sequence()
#                 # break
#                 xp.tap(540, 643)
#                 wait(1)
#             elif find_lv50_cat() is True:
#                 # log("cait 2")
#                 xp.tap(540, 643)
#                 wait(1)
#             else:
#                 # log("normal battle")
#                 run_preset_battle_sequence(battle_sequence)
#                 tap_until_minimap_show(close_menu_btn_coord)
#                 count += 1
#         else:
#             continue
#
#     move_using_worldmap([392, 269])
#     await_black_screen_transition()
#     tap_inn_on_main_screen("b")
#     await_black_screen_transition()
#     recover_in_inn('b')
#     move_using_worldmap([884, 456])
#     await_black_screen_transition()
#     move_using_minimap([264, 599])
#     await_black_screen_transition()
#
